package linz

import linz.log.FuClass
import linz.log.ZiClass
import java.io.File


/**
 * 泛型对象
 */
fun main() {

    val boss = Boss("Alice", 38, 18)
    val boss1 = Boss("张三", 40, 18)
    val boss2 = Boss("李四", 52, 18)

    println(Callback(true, boss).getObj())
    println(Callback(false, boss).getObj() ?: "返回值为null")


    show("")

    val p1 = Genericity(true, 23234234)
    val r = p1.map { it.toString() }

    println(r is String)
    println(r)

    val r3 = map(true, 123) {
        it.toString()
        "map[$it]"
    }

    println(r3)

    //todo Kotlin 泛型类型的约束
    val anyClass = AnyClass("dd")
    val personClass = PersonClass("pp")
    val studentClass = StudentClass("ss")

//    LimitClass(anyClass) error
    LimitClass(studentClass)

    // todo KT 动态参数
    val varArg = VarArg("dd", false, 113213, 34343.45f, null, 'C')
    println(varArg.showObj(0))
    println(varArg.showObj(1))
    println(varArg.showObj(2))
    println(varArg.showObj(3))
    println(varArg.showObj(4))

    //自定义下标
    println(varArg[0])
    println(varArg[1])
    println(varArg[2])
    println(varArg[3])

    //todo  逆变协变
    // ? extends == out 只读不能修改（生产者）
    val list: MutableList<out FuClass> = ArrayList<ZiClass>()
//    list.add(ziClass)
//    list.add(fuClass)

    // ? super == in 只写不能获取（消费者）
    val list2: MutableList<in ZiClass> = ArrayList<FuClass>()
    // todo 泛型限制
    feed(Animal())
    feed(Pig())
    feed(HomePig())
//    free(FuClass()) // 异常

    //传入 函数 （）-> Unit
    feed2(HomePig()::show)
    feed3(HomePig()::toString)




    // todo 1.7.1 _ 可用
    // T is inferred as String because SomeImplementation derives from SomeClass<String>
//    val s = Runner.run<SomeImplementation, _>()
//    assert(s == "Test")
//
//    // T is inferred as Int because OtherImplementation derives from SomeClass<Int>
//    val n = Runner.run<OtherImplementation, _>()
//    assert(n == 42)

}

open class Animal {
    override fun toString(): String {
        return super.toString() + ":: Animal"
    }
}

open class Pig : Animal() {
    override fun toString(): String {
        return "pig"
    }
}

class HomePig : Pig() {
    override fun toString(): String {
        return "家猪"
    }

    fun show() {
        println("==================================")
    }
}

/**
 *  todo 泛型限制为Animal的子类
 */
fun <T : Animal> feed(item: T) = println(item)
fun <T : () -> Unit> feed2(item: T) = item.invoke()
fun <T : () -> String> feed3(item:T) = item.toString()

/**
 * 逆变协变使用
 */
class StudentSetGet<in I, out O> {
    private var item: I? = null

    // 消费者
    fun set(value: I) {
        println("set: $value")
        item = value
    }

    // 生产者
    fun get() = item as? O


}

val fuClass = FuClass()
val ziClass = ZiClass()

//todo 万能对象返回器， Boolean 类控制是否返回
class Callback<T> (private val isR: Boolean, private val obj: T) {
    fun getObj(): T? = obj.takeIf { isR }
}


fun <B> show(item: B) {
    var r = item.also {
        if (it == null) {
            println(" B == null")
        } else {
            println("万能对象是：$it")
        }
    } ?: "=================="

    println("r: $r")
}


class Genericity<T>(val isMap: Boolean = false, val inputType: T) {
    // 模仿RxJava T 输入值 R返回值，R？ 有可能是null
    fun <R> map(mapAction: (T) -> R) = mapAction(inputType).takeIf { isMap }
}

inline fun <T, O> map(isMap: Boolean = true, inputType: T, mapAction: (T) -> O): O? =
    if (isMap) mapAction(inputType) else null

//todo Kotlin 泛型类型的约束
open class AnyClass(name: String)
open class PersonClass(name: String) : AnyClass(name)
class StudentClass(name: String) : PersonClass(name)
class TeacherClass(name: String) : PersonClass(name)


/**
 * T PersonClass的所有子类
 */
class LimitClass<T : PersonClass>(private val inputType: T, private val isR: Boolean = true) {
    fun getObj() = inputType.takeIf { isR }
}

// todo KT 动态参数
class VarArg<T>(vararg objects: T, var isMap: Boolean = true) {
    // out 表示T只能读不能修改 必加
    val objArray: Array<out T> = objects

    fun showObj(index: Int): T? = objArray[index].takeIf { isMap } //?:  "${index} 下标"

    fun <O> mapObj(index: Int, action: (T?) -> O): O? = action(objArray[index].takeIf { isMap })

    // 自定义下标
    operator fun get(index: Int): T? = objArray[index].takeIf { isMap }

}


interface Source<out T> {
    fun nextT(): T
}

fun demo(strs: Source<String>) {
    val objects: Source<Any> = strs // This is OK, since T is an out-parameter
    // ...
}

interface Comparable<in T> {
    operator fun compareTo(other: T): Int
}

fun demo(x: Comparable<Number>) {
    x.compareTo(1.0) // 1.0 has type Double, which is a subtype of Number
    // Thus, you can assign x to a variable of type Comparable<Double>
    val y: Comparable<Double> = x // OK!
}

//Function<*, String> means Function<in Nothing, String>.
//
//Function<Int, *> means Function<Int, out Any?>.
//
//Function<*, *> means Function<in Nothing, out Any?>.

fun readDictionary(file: File): Map<String, *> = file.inputStream().use {
    TODO("Read a mapping of strings to arbitrary elements.")
}

// We saved a map with `Int`s into this file
val intsFile = File("ints.dictionary")

// Warning: Unchecked cast: `Map<String, *>` to `Map<String, Int>`
//@Suppress("UNCHECKED_CAST") //这个可以让编译器不报错
val intsDictionary: Map<String, Int> = readDictionary(intsFile) as Map<String, Int>

// Underscore operator for type arguments
abstract class SomeClass<T> {
    abstract fun execute() : T
}

class SomeImplementation : SomeClass<String>() {
    override fun execute(): String = "Test"
}

class OtherImplementation : SomeClass<Int>() {
    override fun execute(): Int = 42
}

object Runner {
    inline fun <reified S: SomeClass<T>, T> run() : T {
        return S::class.java.getDeclaredConstructor().newInstance().execute()
    }
}